package com.sumer.psychology.common.persistence.mongodb;

import com.mongodb.*;
import com.mongodb.util.JSON;
import com.sumer.psychology.common.Assert;

import java.util.Date;

/**
 * mongodb的资源库
 * <p/>
 * User: zhenguang.zhu
 * Date: 2014/9/29
 * Time: 14:50
 */
public abstract class AbstractMongoRepository {
    MongoApplication mongoApplication;

    protected DB db() {
        return mongoApplication().db();
    }

    /**
     * 初始化要创建的数据
     *
     * @param data data
     * @param key  key
     * @return dbObject
     */
    protected DBObject initializeCreateData(String data, String key) {
        DBObject dbObject = initializeData(data, key);
        dbObject.put("createTime", new Date());

        return dbObject;
    }

    /**
     * 初始化数据
     *
     * @param data data
     * @param key  key
     * @return dbObject
     */
    protected DBObject initializeData(String data, String key) {
        return initializeDataWithNewKey(data, key, "_id");
    }

    /**
     * 初始化数据
     *
     * @param data   data
     * @param key    key
     * @param newKey new key
     * @return dbObject
     */
    protected DBObject initializeDataWithNewKey(String data, String key, String newKey) {
        DBObject dbObject = MongoEventUtil.filterEventObject(
                (DBObject) JSON.parse(data));

        String[] keys = key.split("\\.");

        dbObject.put(newKey, nestedValue(dbObject, keys));
        if (!newKey.equals(keys[0])) {
            dbObject.removeField(keys[0]);
        }

        return dbObject;
    }

    /**
     * 获得嵌套value
     *
     * @param dbObject db object
     * @param keys     keys
     * @return id
     */
    protected String nestedValue(DBObject dbObject, String[] keys) {
        String id = null;
        DBObject keyObject = dbObject;
        for (String subKey : keys) {
            if (subKey.equals(keys[keys.length - 1])) {
                Assert.notNull(keyObject, "键对应的值为空");
                id = (String) keyObject.get(subKey);
            } else {
                keyObject = (DBObject) keyObject.get(subKey);
            }
        }
        return id;
    }

    /**
     * 获得嵌套value
     *
     * @param dbObject db object
     * @param key      key
     * @return id
     */
    protected String nestedValue(DBObject dbObject, String key) {
        String[] keys = key.split("\\.");
        return nestedValue(dbObject, keys);
    }

    /**
     * 查找唯一评论
     *
     * @param id id
     * @return result
     */
    public DBObject findOne(String id) {
        return db().getCollection(dbName()).findOne(idCondition(id));
    }

    /**
     * 根据Id和状态查找
     *
     * @param id   id
     * @param availability availability
     * @return result
     */
    public DBObject findOneWithStatus(String id, String availability) {
        DBObject searchCondition = idCondition(id);
        searchCondition.put("availability", availability);
        return db().getCollection(dbName()).findOne(searchCondition);
    }

    /**
     * 删除唯一评论
     *
     * @param id id
     */
    public void removeOne(String id) {
        db().getCollection(dbName()).remove(idCondition(id));
    }

    /**
     * 序列化成json
     *
     * @param result db cursor
     * @return json
     */
    protected String serialize(DBCursor result) {
        return JSON.serialize(result.toArray());
    }

    /**
     * 序列化成json
     *
     * @param result db object
     * @return json
     */
    protected String serialize(DBObject result) {
        return JSON.serialize(result);
    }

    /**
     * 根据id寻找并序列化
     *
     * @param id id
     * @return json
     */
    public String findById(String id) {
        DBObject dbObject = findOne(id);
        Assert.notNull(dbObject);

        return serialize(dbObject);
    }

    /**
     * 查找作者
     *
     * @param id id
     * @return author id
     */
    public String findAuthorId(String id) {
        DBObject dbObject = findOne(id);
        Assert.notNull(dbObject);

        return (String) dbObject.get("_id");
    }

    /**
     * 获得总数
     *
     * @param queryCondition query condition
     * @return count
     */
    protected int totalCount(DBObject queryCondition) {
        if (queryCondition == null) {
            return db().getCollection(dbName()).find().count();
        } else {
            return db().getCollection(dbName()).find(queryCondition).count();
        }
    }

    /**
     * 带总数量的结果
     *
     * @param queryCondition query condition
     * @param results        results
     * @return results
     */
    protected String serializeWithTotalCount(DBObject queryCondition, Iterable results) {
        return serializeWithTotalCount(totalCount(queryCondition), results);
    }

    /**
     * 带总数的结果
     *
     * @param totalCount total count
     * @param results    results
     * @return results
     */
    protected String serializeWithTotalCount(long totalCount, Iterable results) {
        return JSON.serialize(new BasicDBObject()
                .append("totalCount", totalCount)
                .append("results", results));
    }

    protected abstract String dbName();

    protected DBObject idCondition(String id) {
        return new BasicDBObject("_id", id);
    }

    public void setMongoApplication(MongoApplication mongoApplication) {
        this.mongoApplication = mongoApplication;
    }

    private MongoApplication mongoApplication() {
        return mongoApplication;
    }
}
